Published on

Serializing PHP Entities to JSON

Authors
Socials
Address
Company details
header image

So, as I fetch object from the database by using ORM and I might sometimes return results via REST. This means usually I end up mapping getters to array. This seems boring, time consuming, stupid. So I said enough of this and started looking for a solution.

The requirement was simple. Solution which makes possible to get entity values as array automatically. (As arrays can be always encoded into JSON). This would need reflection, but I decided already go lazy way, so performance loss is accepted. If you want high performance, you should just stay manually writing entities to array.


Solution

So I wrote the class. Source for this class is available here. The idea is to input EntityToArray::convert(object $entity)and output entity as array. The idea is to find all getters and call those. The key of the array will taken automatically from the name of property. The basic flow for the conversion is following.

This is the basic principle how it will work. Very simple, but a lot of looping and reflections. This means it will be a lot slower than just doing it manually. However, like said, this is not about performance.

Usage

It is easier to show the code first and talk after that. So in bellow example I’m going to declare two entities, Country and Flag. Every country needs a flag, so does our example Country also need a flag as a entity.

Entity: Flag

php
// Our Entities
final class Flag
{
    /** @var string */
    private $mainColor;

    /** @var int */
    private $height;

    /** @var int */
    private $width;

    /** @var bool */
    private $registered;

    public function __construct(
        string $mainColor,
        int $height,
        int $width,
        bool $registered
    )
    {
        $this->mainColor = $mainColor;
        $this->height = $height;
        $this->width = $width;
        $this->registered = $registered;
    }

    public  function getMainColor(): string
    {
        return $this->mainColor;
    }

    public  function getHeight(): int
    {
        return $this->height;
    }

    public  function getWidth(): int
    {
        return $this->width;
    }

    public  function getRegistered(): bool
    {
        return $this->registered;
    }
}

Entity: Country

php
// It is not mandatory to extend. Only if you want benefit from
// implementing \JsonSerializable and having toArray, toJson methods.
final class Country extends \Niko9911\Serializable\Serializable
{
    // If you don't want implement \JsonSerializable,
    // but you want methods `toArray & toJson` into
    // you entity, you can add this trait.
    use \Niko9911\Serializable\SerializableTrait;

    /** @var string  */
    private $name;

    /** @var int  */
    private $id;

    /** @var Flag */
    private $flag;

    public function __construct(string $name, int $id, Flag $flag)
    {
        $this->name = $name;
        $this->id = $id;
        $this->flag = $flag;
    }

    public function getName(): string
    {
        return $this->name;
    }

    public function getId(): int
    {
        return $this->id;
    }

    public function getFlag(): Flag
    {
        return $this->flag;
    }
}

Explaining the usage

Now we have declared the entities and you know what we are going to map into array and into JSON. First, let’s create instance of a Entity.

php
$entity = new Country('Finland', 358, new Flag('Blue', 150, 245, true));

So now we have new entity with values in the properties and getters set. Now we just want values in format of array. This can be done easily just by calling our static function.

php
$result1 = \Niko9911\Serializable\EntityToArray::convert($entity);
var_dump($result1);
/**
[
  'name'=>self::NAME,
  'id'=>self::CODE,
  'flag'=>
 [
   'mainColor'=>self::MAIN,
   'height' => 150,
   'width' =>  245,
   'registered'=>true,
   'options'=>[]
  ]
]
*/

// And now you can just get json by doing following
\json_encode($result1);

Advanced

Okey, that was easy. Do you remember how we did extend Serializable in the Country class? Well, that is how we can make sure our class also implements \JsonSerializable. This is automatically made when you extend the class. Also this will add two new useful functions into your class when you extend it toJson(): and toArray(): array. Example how to take advantage of these functions is bellow.

php
$result2 = $entity->toArray();
$result3 = $entity->toJson();
$result4 = \json_encode($entity);

var_dump($result1);
/**
[
  'name'=>self::NAME,
  'id'=>self::CODE,
  'flag'=>
 [
   'mainColor'=>self::MAIN,
   'height' => 150,
   'width' =>  245,
   'registered'=>true,
   'options'=>[]
  ]
]
**/
var_dump($result1 === $result2); // True

var_dump($result3);
/**
{"name":"Finland","id":358,"flag":{"options":[],"mainColor":"Blue","height":150,"width":245,"registered":true}}
**/

var_dump($result3 === $result4); // True

/** END **/

Summary

Should I use this? Well, it depends. In case you want just develop something quickly and performance is not most critical, then you can use this. However, I would still agree to write Entities to array manually when doing REST responses. Just prevent exposing data what you should not expose, but you exposed due it was automatically put there.

Loops, loops and loops. Biggest issue of this library. You’re creating reflections and looping trough the properties. Like, just think about it. You have 10 properties plus two properties which are also entities and those have 10 another properties totaling about 30 properties. Also there could be 5 arrays in total. (Now there is total 35 properties.) This means this code will looped 35 times, plus all array items plus creating Reflections on every object. Not good.

However, if you can accept this performance loss, just go for it. I’m doing my freetime non-critical apps in PHP like bots, hobby sites, etc. Nothing critical and those will never scale into level of enterprise applications. Also I’m 99.9% of the time working on those projects alone. This means everything what saves my time from typing entities with 35 properties manually into array is welcome.

Pros

  • Faster development
  • Good for small applications

Cons

  • Bad performance
  • Can lead into data expose if not used correctly

Notice

Source is available in Github and Packagist, but due of this beign legacy and I will not anymore link it here.